<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>装箱和拆箱</title>
</head>
<body>
    <script>
        console.log('----------------------------------------------------------------------------------------------------------------')
        /*
            装箱：将基本数据类型转换为对应的引用类型的操作，分为显示装箱和隐式装箱
        */ 
        // 隐式装箱
        
        var s1 = 'call_me_R';   // 隐式装箱
        var s2 = s1.substring(2);
       
        s1.gender = 'female';
        s1.sayGender = function() {
            console.log('I am a', s1.gender);
        };

        /*
            隐式装箱当读取一个基本类型值时，后台会创建一个该基本类型所对应的基本包装类型对象
            在这个基本类型的对象上调用方法，其实就是在这个基本类型对象上调用方法
            这个基本类型的对象是临时的，它只存在于方法调用那一行代码执行的瞬间，执行方法后立即被销毁
            这也是在基本类型上添加属性和方法会不识别或报错的原因了
        */

        console.log('gender', s1.gender);   // gender undefined
        // s1.sayGender();   // s1.sayGender is not a function

        /*
            1. 创建String实例的一个实例
            2. 在实例中调用指定的方法
            3. 销毁实例
        */ 

        // 相当于
        // #1
        var s1 = new String('call_me_R');
        // #2
        var s2 = s1.substring(2);
        // #3
        s1 = null;


        // 显示装箱
        /*
            显示装箱的操纵可以对new出来的对象进行属性和方法的添加啦
            因为通过通过new操作符创建的引用类型的实例
            在执行流离开当前作用域之前一直保留在内存中
        */
       var s3 = new String('I am a beautiful girl.');
       s3.job = 'student';
       s3.sayJob =  function() {
           console.log('Hello my job is', s3.job);
       };

       console.log('job',s3.job);  // job student
       s3.sayJob();   // Hello my job is student

       console.log('----------------------------------------------------------------------------------------------------------------')

       // 拆箱
       /*
            把引用数据类型转换为基本的数据类型，通常通过引用valueOf()和toString()的方法实现
       */
       var objNum = new Number(64);
       var objStr = new String('64');
       console.log(objNum);    // Number{64}
       console.log(objStr);    // String{64}
       console.log(typeof objNum);   // object
       console.log(typeof objStr);   // object

       // # 拆箱
       console.log(objNum.valueOf());   // 64
       console.log(objNum.toString());  // '64'
       console.log(typeof objNum.valueOf());  // number
       console.log(typeof objStr.toString());  // string 

       console.log(objStr.valueOf());   // '64'
       console.log(objStr.toString());  // '64'
       console.log(typeof objStr.valueOf());  // string
       console.log(typeof objStr.toString());  // string 
       
    </script>
</body>
</html>